﻿#ifndef FDTHREAD__H
#define FDTHREAD__H
#pragma once

#include "kernel/event/event.h"
#include "kernel/threading/mutex.h"

#include <stdio.h>
#include <map>
#if defined(__OS_LINUX__) || defined(__OS_CYGWIN__)||defined (__OS_IOS__)
#include <pthread.h>
#include <sys/time.h>
#include <errno.h>
#include <unistd.h>
#endif

#if defined(__i386) || defined(_M_IX86)
// Calling conventions are needed for x86 (32-bit ONLY) CPUs
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define OGRE_THREAD_CALL_CONVENTION _OGRE_SIMD_ALIGN_ATTRIBUTE __stdcall
#elif OGRE_COMPILER == OGRE_COMPILER_GNUC || OGRE_COMPILER == OGRE_COMPILER_CLANG
#define __cdecl __attribute__((__cdecl__))
#define OGRE_THREAD_CALL_CONVENTION __cdecl
#endif
#else
#define OGRE_THREAD_CALL_CONVENTION
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
/// @See Threads::CreateThread for an example on how to use
#define THREAD_DECLARE( threadFunction ) \
	unsigned long OGRE_THREAD_CALL_CONVENTION threadFunction##_internal( void *argName )\
	{\
	unsigned long retVal = 0;\
	FD::Kernel::ThreadHandle *threadHandle( reinterpret_cast<FD::Kernel::ThreadHandle*>( argName ) );\
	try {\
	retVal = threadFunction( threadHandle );\
		}\
		catch( ... )\
		{\
		}\
		delete threadHandle;\
		return retVal;\
	}
#else
/// @See Threads::CreateThread for an example on how to use
#define THREAD_DECLARE( threadFunction ) \
	void* OGRE_THREAD_CALL_CONVENTION threadFunction##_internal( void *argName )\
	{\
	unsigned long retVal = 0;\
	FD::Kernel::ThreadHandle *threadHandle( reinterpret_cast<FD::Kernel::ThreadHandle*>( argName ) );\
	try {\
	retVal = threadFunction( threadHandle );\
		}\
		catch( ... )\
		{\
		}\
		delete threadHandle;\
		\
		return 0;\
	}
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
//No need to include the heavy windows.h header for something like this!
typedef void* HANDLE;
#else
#include <pthread.h>
#endif

#include <vector>

using namespace std;
#include "kernel/ref_ptr.h"

namespace FD
{
	namespace Kernel
	{
		class FD_Kernel_Export ThreadHandle : public FD::Kernel::CReferenced
		{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
			HANDLE  mThread;
#else
			pthread_t mThread;
#endif
			size_t  mThreadIdx;
			void    *mUserParam;

		public:
			ThreadHandle( size_t threadIdx, void *userParam );
			~ThreadHandle();

			size_t getThreadIdx() const         { return mThreadIdx; }
			void* getUserParam() const          { return mUserParam; }

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
			/// Internal use
			void _setOsHandle( HANDLE handle )  { mThread = handle; }
			/// Internal use
			HANDLE _getOsHandle() const         { return mThread; }
#else
			/// Internal use
			void _setOsHandle( pthread_t &handle )  { mThread = handle; }
			/// Internal use
			pthread_t _getOsHandle() const          { return mThread; }
#endif
		};

		typedef FD::Kernel::ref_ptr<ThreadHandle> ThreadHandlePtr;
		typedef std::vector<ThreadHandlePtr> ThreadHandleVec;

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		typedef unsigned long (OGRE_THREAD_CALL_CONVENTION *THREAD_ENTRY_POINT)( void *lpThreadParameter );
#else
		typedef void* (OGRE_THREAD_CALL_CONVENTION *THREAD_ENTRY_POINT)( void *lpThreadParameter );
#endif

		class FD_Kernel_Export Threads
		{
		public:
#define THREAD_GET( threadFunction ) threadFunction##_internal
			/** Creates and executes a new thread
			@remarks
			The function to execute must be declared via THREAD_DECLARE, and the first argument
			must be provided through THREAD_GET. The following example shows how to use:

			unsigned long myOwnThread( ThreadHandle *ownThreadHandle )
			{
			//Should print "Hello from thread 50"
			printf( "Hello from thread %i", ownThreadHandle.getThreadIdx() );
			return 0;
			}
			THREAD_DECLARE( myOwnThread );

			int main()
			{
			ThreadHandle handle = CreateThread( THREAD_GET( myOwnThread ), 50, 0 );
			WaitForThreads( 1, handle );
			return 0;
			}

			It is not possible to retrieve the return value of the function because it's not
			portable (and trying to emulate it induces to easy-to-cause memory leaks; as
			we're dealing with C functions + potential race conditions, not C++)
			@param entryPoint
			Function name of the entry point. VERY IMPORTANT: The entry point must be provided
			by THREAD_GET. Do not use a function directly, otherwise there will be memory leaks!
			@param threadIdx
			Optional index for this thread (ie. when you have many worker threads to work on a
			section of data.
			@param param
			Optional argument to be passed.
			@return
			Handle to created thread.
			*/
			static ThreadHandlePtr CreateThread( THREAD_ENTRY_POINT entryPoint,
				size_t threadIdx, void *param );

			/** Waits until all threads are finished
			@param numThreadInfos
			Number of ThreadHandle passed in the array as 'threadHandles'
			@param threadHandles
			Array of numThreadHandles or more ThreadHandle
			@remarks
			Don't pass more than 128 handles per call
			*/
			static void WaitForThreads( size_t numThreadHandles, const ThreadHandlePtr *threadHandles );
			static void WaitForThreads( const ThreadHandleVec &threadHandles );
		};

		struct FD_THREAD_DATA;
		/// <summary>
		/// 线程的局部存储
		/// </summary>
		template <class T>
		class ThreadLocalStore
		{
		public:
			ThreadLocalStore()
#if defined(__OS_WIN__)
				: m_dwTlsIndex(0)
#endif
			{
#if defined(__OS_WIN__)
				if ((m_dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
				{
					ExitProcess(0);
				}
#elif defined(__OS_LINUX__) || defined(__OS_CYGWIN__)||defined (__OS_IOS__)
				pthread_key_create(&m_tlsIndex, NULL);
#endif
			}
			~ThreadLocalStore()
			{
#if defined(__OS_WIN__)
				if (m_dwTlsIndex)
				{
					TlsFree(m_dwTlsIndex);
				}
#elif defined(__OS_LINUX__) || defined(__OS_CYGWIN__) ||defined (__OS_IOS__)
				pthread_key_delete(m_tlsIndex);
#endif
			}
			/// <summary>
			/// 获得线程局部数据指针
			/// </summary>
			/// <param name="id">线程的id</param>
			/// <returns>线程局部数据指针</returns>
			T *getValue()
			{
#if defined(__OS_WIN__)
				LPVOID lpvData = TlsGetValue(m_dwTlsIndex);
				return (T *)lpvData;
#elif defined(__OS_LINUX__) || defined(__OS_CYGWIN__) ||defined (__OS_IOS__)
				return (T *)pthread_getspecific(m_tlsIndex);
#endif
			}
			/// <summary>
			/// 设置线程局部数据指针
			/// </summary>
			/// <param name="value">线程局部数据指针</param>
			/// <returns>/<returns>
			void setValue(T *ptr)
			{
#if defined(__OS_WIN__)
				if (! TlsSetValue(m_dwTlsIndex, ptr))
				{
					ExitProcess(0);
				}
#elif defined(__OS_LINUX__) || defined(__OS_CYGWIN__) ||defined (__OS_IOS__)
				pthread_setspecific(m_tlsIndex, ptr);
#endif
			}
			/// <summary>
			/// 清除所有线程局部存储数据
			/// </summary>
			/// <param name="">线程的id</param>
			/// <returns></returns>
			void reset()
			{
#if defined(__OS_WIN__)
				T *lpvData = (T *)TlsGetValue(m_dwTlsIndex);
#elif defined(__OS_LINUX__) || defined(__OS_CYGWIN__) ||defined (__OS_IOS__)
				T *lpvData = (T *)pthread_getspecific(m_tlsIndex);
#endif
				if (lpvData)
				{
					delete lpvData;
				}
			}
		private:
#if defined(__OS_WIN__)
			unsigned long/*DWORD*/ m_dwTlsIndex;
#elif defined(__OS_LINUX__) || defined(__OS_CYGWIN__) ||defined (__OS_IOS__)
			pthread_key_t m_tlsIndex;
#endif
		};
		enum ThreadPriority
		{
			FD_THREAD_LOW,
			FD_THREAD_NORMAL,
			FD_THREAD_HIGH,
			FD_THREAD_REAL
		};
		enum ThreadState
		{
			TS_CREATED,
			TS_RUNNING,
			TS_SUSPENDED,
			TS_TERMINATED,
			TS_FINISHED
		};
		class Thread;
		class FD_Kernel_Export ThreadFunc : public FD::Kernel::CReferenced
		{
		public:
			ThreadFunc();
			virtual ~ThreadFunc();
			virtual void run();
		protected:
			void operator()();
			friend class Thread;
		};
		/// <summary>
		/// 线程的基类，可以通过继承此类并重载run方法开启线程
		/// 也可以直接调用work方法将线程函数指针传递进去，运行线程
		/// </summary>
		class FD_Kernel_Export Thread : public FD::Kernel::EventObject
		{
		public:
			Thread();
			virtual ~Thread();
			/// <summary>
			/// 开始运行线程，调用此接口时，必须继承此类并重载run方法
			/// </summary>
			/// <param name=""></param>
			/// <returns>成功返回true,否则false</returns>
			bool start();

			/// <summary>
			/// 开始运行线程，调用此接口时，不需要继承此类，
			///之间将线程函数的指针传递给该接口的第一个参数即可
			/// </summary>
			/// <param name="pFunc">线程函数的指针</param>
			/// <param name="pParam">线程函数的参数</param>
			/// <returns>成功返回true,否则false</returns>
			bool work(FD::Kernel::ThreadFunc *threadFunc);

			/// <summary>
			/// 等待线程运行结束
			/// </summary>
			/// <param name=""></param>
			/// <returns>成功返回true,否则false</returns>
			bool wait();
			/// <summary>
			/// 让线程休息指定的时间
			/// </summary>
			/// <param name="msecs">线程休息时间的毫秒数</param>
			/// <returns></returns>
			static void sleep(uint32 msecs);

			/// <summary>
			/// 让线程休息指定的时间
			/// </summary>
			/// <param name="microsec">线程休息时间的微秒数</param>
			/// <returns></returns>
			static int microSleep(uint32 microsec);
			/// <summary>
			/// 强制结束线程
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			void terminate();
			/// <summary>
			/// 判断线程是否正在运行
			/// </summary>
			/// <param name=""></param>
			/// <returns>正在运行返回true,否则返回false</returns>
			bool isRunning();
			/// <summary>
			/// 设置线程的优先级
			/// </summary>
			/// <param name="priority">线程优先级的枚举值</param>
			/// <returns></returns>
			void setThreadPriority(ThreadPriority priority);
			/// <summary>
			/// 设置线程的继承属性
			/// </summary>
			/// <param name="inherit">inherit为true,则子线程继承于父线程，否则不继承</param>
			/// <returns></returns>
			void setThreadInheritAttr(bool inherit);
			/// <summary>
			/// 获得当前线程的ID
			/// </summary>
			/// <param name=""></param>
			/// <returns>返回当前线程的ID</returns>
			static uint32 getThreadID();

			void suspend();
			void resume();
			/// <summary>
			/// 获得线程的运行状态
			/// </summary>
			/// <param name=""></param>
			/// <returns>线程的运行状态枚举值</returns>
			int32 getThreadState();
			/// <summary>
			/// 设置线程的运行状态
			/// </summary>
			/// <param name="state">线程运行状态枚举值</param>
			/// <returns></returns>
			void setThreadState(ThreadState state);
			/// <summary>
			/// 获得线程的返回值
			/// </summary>
			/// <param name=""></param>
			/// <returns>线程的运行完毕的返回值</returns>
			int32 getRetValue();
			/// <summary>
			/// 获得当前线程的指针
			/// </summary>
			/// <param name=""></param>
			/// <returns>当前线程的指针</returns>
			static FD::Kernel::Thread *getCurrentThread();
			/// <summary>
			/// 获得线程已开启的线程个数
			/// </summary>
			/// <param name=""></param>
			/// <returns>线程个数</returns>
			static uint32 getThreadCount();

			static bool isMainThread();
		public:
			virtual int32 run() ;
		private:
			FD_THREAD_DATA *m_pData;
			static uint32 mMainThreadID;
			friend struct FD_THREAD_DATA;
		};

		/** Template for per-thread data storage */
		template<typename T>
		struct PerThread
		{
			T& get()
			{
				MutexLocker lock(&_mutex);
				unsigned tid = Thread::getThreadID();
				return _data[tid];
			}
		private:
			std::map<unsigned,T> _data;
			RecursiveMutex     _mutex;
		};
	}
}

#endif

